package fxification.test;

import junit.framework.TestCase;
import fxification.async.Task;
import junit.framework.Assert;
import junit.textui.TestRunner;
import java.lang.RuntimeException;
import java.lang.Throwable;

/**
 * @author vvivien
 */

public class TaskTest extends TestCase {
    public function testTaskWork(): Void {
        def taskRunner = Task{
            work:function():Object{
                1 + 2
            }
        }
        Assert.assertNotNull("Action property not set", taskRunner.work);
        var result = taskRunner.work();
        Assert.assertTrue("Action fn not invoked correctly", result == 3);
    }

    public function testTaskOnStart() : Void {
        var started = true;
        Task{
            work:function():Object{
                2 + 2;
            }
            onStart:function() {
                Assert.assertTrue("OnStarted is not being called", started);
            }
        }.start();
    }
    public function testTaskStartedFlag() : Void {
        def task:Task = Task{
            work:function():Object{
                2 + 2;
            }
            onStart:function() {
                Assert.assertTrue("Started flag is not being set properly", task.started);
                Assert.assertTrue("Stopped is not being set properly", not task.stopped);
                Assert.assertTrue("Done is not being set properly", not task.done);
                Assert.assertTrue("Succeeded is not being set properly", not task.succeeded);
            }
        }
        task.start();
    }

    public function testTaskOnDone() : Void {
        var result = 0;
        Task{
            work:function():Object{
                result = 2 + 2;
            }
            onDone:function() {
                Assert.assertTrue("OnDone fn not invoked correctly", result == 4);
            }

        }.start();
    }

    public function testTaskDoneFlag() : Void {
        def task:Task = Task{
            work:function():Object{
                2 + 2;
            }
            onStart:function() {
                Assert.assertTrue("Started flag is not being set properly", task.started);
                Assert.assertTrue("Stopped is not being set properly", not task.stopped);
                Assert.assertTrue("Done is not being set properly", not task.done);
            }
            onDone:function() {
                Assert.assertTrue("Started flag is not being set properly", task.started);
                Assert.assertTrue("Stopped is not being set properly", not task.stopped);
                Assert.assertTrue("Done is not being set properly", task.done);
            }
        }
        task.start();
    }


    public function testTaskOnSucceeded() : Void {
        Task{
            work:function():Object{
                2 + 2;
            }
            onSucceeded:function(result:Object) {
                Assert.assertTrue("OnSucceeded fn not invoked correctly", result == 4);
            }

        }.start();
    }

    public function testTaskSucceededFlag() : Void {
        def task:Task = Task{
            work:function():Object{
                2 + 2;
            }
            onStart:function() {
                Assert.assertTrue("Started flag is not being set properly", task.started);
                Assert.assertTrue("Done is not being set properly", not task.succeeded);
            }
            onSucceeded:function(result:Object) {
                Assert.assertTrue("OnSucceeded fn not invoked correctly", result == 4);
                Assert.assertTrue("Started flag is not being set properly", task.started);
                Assert.assertTrue("Done is not being set properly", task.done);
            }
        }
        task.start();
    }


    public function testTaskOnStopped() : Void {
        var sum = 0;
        def task = Task{
            work:function():Object{
                sum = 2 + 2;
            }
            onStop:function() {
                Assert.assertTrue("OnStopped fn not invoked correctly", sum == 4);
            }
        };
        task.start();
        java.lang.Thread.currentThread().sleep(300.00); // let some fibbo calculated
        task.stop();
    }
    
    public function testTaskStoppedFlag() : Void {
        def task:Task = Task{
            work:function():Object{
                var fibbo = 0;
                for(i in [0..99]){
                    if(not task.stopped){
                        fibbo = fibbo + fib(i);
                    }
                    else{
                        break;
                    }
                }
                fibbo;
            }
        }
        task.onStart=function() {
            Assert.assertTrue("Started flag is not being set properly", task.started);
            Assert.assertTrue("Stopped is not being set properly", not task.stopped);
            Assert.assertTrue("Done is not being set properly", not task.done);
        }
        task.onStop=function() {
            println ("started = {task.started}, stopped = {task.stopped}, done = {task.done}");
            Assert.assertTrue("Stopped is not being set properly", task.stopped);
            Assert.assertTrue("Done is not being set properly", task.done);
            Assert.assertTrue("Succeeded is not being set properly", not task.succeeded);
        }
        
        task.start();
        java.lang.Thread.currentThread().sleep(300.00); // let some fibbo calculated
        task.stop();
    }

    public function fib(n:Number):Integer {
        if (n <= 1) return n;
        return fib(n-1) + fib(n-2);
    }


    public function testTaskOnFailure() : Void {
        def task:Task = Task{
            work:function():Object{
                throw new RuntimeException("Error");
            }
            onFailure:function(ex:Throwable) {
                Assert.assertNotNull("OnFailure not receiving Throwable", ex);
                Assert.assertTrue("OnFailure returning wrong Throwable type", ex instanceof RuntimeException);
                Assert.assertNotNull("CauseOfFailure object not found.", task.causeOfFailure);
                Assert.assertNotNull("Failed flag not set properly.", task.failed);
            }
        };
        task.start();
    }
}

public function run() {
    def test = TestRunner{};
    test.run(test.getTest(TaskTest.class.getName()));
}